//
//  SVIndefiniteAnimatedView.swift
//  Valentine-Swift
//
//  Created by 陆文宇 on 2017/1/31.
//  Copyright © 2017年 陆文宇. All rights reserved.
//

import UIKit

class SVIndefiniteAnimatedView: UIView {
    
    override var frame: CGRect {
        set {
            if frame != super.frame {
                super.frame = frame
                
                if superview != nil {
                    layoutAnimatedLayer()
                }
            }
        }
        
        get {
            return super.frame
        }
    }
    
    var radius: CGFloat {
        willSet {
            if radius != newValue {
                indefiniteAnimatedLayer.removeFromSuperlayer()
                let arcCenter: CGPoint = CGPoint(x: newValue + strokeThickness / 2 + 5, y: newValue + strokeThickness / 2 + 5)
                let smoothedPath: UIBezierPath = UIBezierPath(arcCenter: arcCenter, radius: newValue, startAngle: CGFloat.pi * 3 / 2, endAngle: CGFloat.pi / 2 + CGFloat.pi * 5, clockwise: true)
                indefiniteAnimatedLayer.path = smoothedPath.cgPath
                addAnimation()
                
                if superview != nil {
                    layoutAnimatedLayer()
                }
            }
        }
    }
    var strokeThickness: CGFloat {
        willSet {
            indefiniteAnimatedLayer.lineWidth = newValue
        }
    }
    var strokeColor: UIColor {
        willSet {
            indefiniteAnimatedLayer.strokeColor = newValue.cgColor
        }
    }
    
     var indefiniteAnimatedLayer: CAShapeLayer = {
        let _indefiniteAnimatedLayer: CAShapeLayer = CAShapeLayer()
        _indefiniteAnimatedLayer.contentsScale = UIScreen.main.scale
        _indefiniteAnimatedLayer.fillColor = UIColor.clear.cgColor
        _indefiniteAnimatedLayer.lineCap = kCALineCapRound
        _indefiniteAnimatedLayer.lineJoin = kCALineJoinBevel
        return _indefiniteAnimatedLayer
    }()
    init(frame: CGRect, radius: CGFloat, strokeThickness: CGFloat, strokeColor: UIColor) {
        self.radius = radius
        self.strokeThickness = strokeThickness
        self.strokeColor = strokeColor
        
        super.init(frame: frame)
        
        reInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func reInit() -> Void {
        let arcCenter: CGPoint = CGPoint(x: radius + strokeThickness / 2 + 5, y: radius + strokeThickness / 2 + 5)
        let smoothedPath: UIBezierPath = UIBezierPath(arcCenter: arcCenter, radius: radius, startAngle: CGFloat.pi * 3 / 2, endAngle: CGFloat.pi / 2 + CGFloat.pi * 5, clockwise: true)
        indefiniteAnimatedLayer.frame = CGRect(x: -arcCenter.x, y: -arcCenter.y, width: arcCenter.x * 2, height: arcCenter.y * 2)
        indefiniteAnimatedLayer.strokeColor = strokeColor.cgColor
        indefiniteAnimatedLayer.lineWidth = strokeThickness
        indefiniteAnimatedLayer.path = smoothedPath.cgPath
        
        addAnimation()
    }
    
    
    func addAnimation() -> Void {
        let maskLayer: CALayer = CALayer()
        
        let bundle: Bundle = Bundle(for: SVProgressHUD.self)
        let url: URL = bundle.url(forResource: "SVProgressHUD", withExtension: "bundle")!
        let imageBundle: Bundle = Bundle(url: url)!
        
        let path: String = imageBundle.path(forResource: "angle-mask", ofType: "png")!
        
        maskLayer.contents = UIImage(contentsOfFile: path)?.cgImage
        maskLayer.frame = indefiniteAnimatedLayer.bounds
        indefiniteAnimatedLayer.mask = maskLayer
        
        let animationDuration: TimeInterval = 1
        let linearCurve: CAMediaTimingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        
        let animation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation")
        animation.fromValue = 0
        animation.toValue = CGFloat.pi * 2
        animation.duration = animationDuration
        animation.timingFunction = linearCurve
        animation.isRemovedOnCompletion = false
        animation.repeatCount = Float.infinity
        animation.fillMode = kCAFillModeForwards
        animation.autoreverses = false
        indefiniteAnimatedLayer.mask?.add(animation, forKey: "rotate")
        
        let animationGroup: CAAnimationGroup = CAAnimationGroup()
        animationGroup.duration = animationDuration
        animationGroup.repeatCount = Float.infinity
        animationGroup.isRemovedOnCompletion = false
        animationGroup.timingFunction = linearCurve
        
        let strokeStartAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeStart")
        strokeStartAnimation.fromValue = 0.015
        strokeStartAnimation.toValue = 0.515
        
        let strokeEndAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
        strokeEndAnimation.fromValue = 0.485
        strokeEndAnimation.toValue = 0.985
        
        animationGroup.animations = [strokeStartAnimation, strokeEndAnimation]
        indefiniteAnimatedLayer.add(animationGroup, forKey: "progress")
    }
    
    override func willMove(toSuperview newSuperview: UIView?) {
        if newSuperview != nil {
            layoutAnimatedLayer()
        } else {
            indefiniteAnimatedLayer.removeFromSuperlayer()
        }
    }
    
    func layoutAnimatedLayer() {
        let layer: CALayer = indefiniteAnimatedLayer
        self.layer.addSublayer(layer)
        
        let widthDiff: CGFloat = bounds.width - layer.bounds.width
        let heightDiff: CGFloat = bounds.height - layer.bounds.height
        layer.position = CGPoint(x: bounds.width - layer.bounds.width / 2 - widthDiff / 2, y: bounds.height - layer.bounds.height / 2 - heightDiff / 2)
    }
    
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        return CGSize(width: (radius + strokeThickness / 2 + 5) * 2, height: (radius + strokeThickness / 2 + 5) * 2)
    }


    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

}
